This document aims to show how to transform geographic coordinates to and from screen coordinates for a map projection in Diana.
To get access to the Python modules that expose Diana's plotting features, you need to install the python-diana
package from the local package repository. Either use the package manager to do this, or enter the following in a
terminal:
apt-get install python-diana
Some examples can also be found in the python-diana-examples
package.
You can use Diana's functionality from Python by importing the bdiana
and plotcommands
modules from the metno
package. If you are using an old version of ipython (earlier than
version 1.0) then it is also useful to import the embed
function from the
metno.ipython_extensions
module. The pyproj
module is used to describe projections in a
way that Diana understands. We also import the datetime
module so that we can pass a time
to Diana without needing to obtain one from a data file.
In [1]:
# Import the modules needed to use Diana.
from metno import bdiana, plotcommands
# Import an extension that lets us embed an image into a worksheet.
from metno.ipython_extensions import embed
import datetime, pyproj
The bdiana
module contains the BDiana
class. This provides a convenient interface to Diana's functions and also
wraps several initialisation steps into one object. To start using Diana, we simply create an instance of this class
and load a setup file that describes where various resources are located and set it up
using a setup file located on the user's system.
In [2]:
b = bdiana.BDiana()
b.setup("/etc/diana/setup/diana.setup-COMMON")
In [3]:
a = plotcommands.Area(name="S-Norge")
m = plotcommands.Map(map="Gshhs-Auto", backcolour="white", land="on")
m.setOption("land.colour", "flesh")
b.setPlotCommands([a.text(), m.text()])
b.setPlotTime(datetime.datetime.now())
im = b.plotImage(500, 500)
embed(im)
We obtain the area shown by the plot.
In [4]:
area = b.getPlotArea()
This area is comprised of a projection and a rectangle. We obtain these so that we can work with them.
In [5]:
p = area.P()
r = b.getPlotSize()
We create a new Proj
object to describe the projection since this is convenient to use
from Python.
In [6]:
pr = pyproj.Proj(p.getProjDefinition())
In [7]:
from PyQt4.QtCore import Qt, QRect
from PyQt4.QtGui import QFont, QFontMetricsF, QPainter
We want to display the location of Bergen on the image, so we first obtain the
projection coordinates from the geographic coordinates using the Proj
object we
created.
In [8]:
lat = 60.0 + 23.0/60 + 34.0/3600
lon = 5.0 + 19.0/60 + 26.0/3600
x, y = pr(lon, lat)
Since we know the extent of the plotting area (the rectangle) and the size of the image, we can easily transform the projection coordinates to screen (or image) coordinates.
In [9]:
sx = (x - r.x1)/(r.x2 - r.x1) * im.width()
sy = (y - r.y2)/(r.y1 - r.y2) * im.height()
Now we can paint something on the image. We take a copy first, then use QPainter
to
draw an ellipse at the desired location.
In [10]:
im2 = im.copy()
radius = 8
p = QPainter()
p.begin(im2)
p.setRenderHint(QPainter.Antialiasing)
p.setBrush(Qt.white)
p.drawEllipse(sx - radius, sy - radius, radius * 2, radius * 2)
p.end()
embed(im2)
We can also display text. We take a copy of the new image, determine the width of the text, and draw the text centred in a rectangular area just to the left of the ellipse.
In [11]:
im3 = im2.copy()
f = QFont()
fm = QFontMetricsF(f)
width = fm.width("Bergen")
p = QPainter()
p.begin(im3)
p.drawText(QRect(sx - width - 20, sy - fm.height()/2, width, fm.height()),
Qt.AlignCenter, "Bergen")
p.end()
embed(im3)
In [12]:
cx, cy = im.width()/2.0, im.height()/2.0 # note use of floats
x = r.x1 + (r.x2 - r.x1) * (cx / im.width())
y = r.y2 + (r.y1 - r.y2) * (cy / im.height())
x, y
In [13]:
lon, lat = pr(x, y, inverse = True)
lat, lon